<template>
  <div class="lab-table">
    <draggable class="lab-table-drag"
               v-if="labDesign.switch" v-model="element.elements" :setData="()=>{}"
               v-bind="{group:'people', ghostClass: 'ghost',animation: 200, handle: '.drag-element'}"
               @add="onDragAdd" style="height: 40px;width: 100%;min-height: 50px"
    >
    </draggable>
<!--  height: '用于固定表头',max-height: '实现流体高度'  -->
    <el-table :data="dataSource" border v-loading="requesting" :row-key="element.props.rowKey"
              :height="element.props.height" :max-height="element.props.maxHeight" lazy
              @select="select" @select-all="selectAll" @row-click="rowClick" highlight-current-row
    >
      <el-table-column v-if="element.props.showIndex" type="index" label="序号" width="50" align="center" />
      <el-table-column v-if="element.props.selectBox" type="selection" label="选择" width="50" align="center" />
      <el-table-column v-if="element.props.showExpand" type="expand" label="展开" width="50" align="center" >
        <template slot-scope="scope">
          <lab-view :element="element.elements.find(item => item.render === 'view')" :model-data="scope.row" />
        </template>
      </el-table-column>
      <template v-for="(column,itemIndex) in element.elements" >
        <el-table-column v-if="column.key && column.visible && ['all', 'table'].includes(column.lifeScope)" :key="column.key" :prop="column.mapper"
                         :width="(labDesign.switch && (!column.props.tableWidth || column.props.tableWidth < 200)) ? 200 : column.props.tableWidth" :label="column.label" align="center" >
          <template slot="header" slot-scope="scope">
            <span>{{ column.label }}</span>
            <div v-if="scope && filterElements[column.mapper]" @click.stop="() => {return false}">
              <lab-element :element="filterElements[column.mapper]" :model-data="filterModel" />
            </div>
          </template>
          <template slot-scope="scope">
            <div :class="{ 'drag-element': labDesign.switch, 'active': labDesign.switch && labDesign.activity.key === column.key }"
                 @click.stop="labDesign.activeChange(column, element.elements, itemIndex)">
              <lab-element :element="column" :index="itemIndex" :elements="element.elements" :model-data="scope.row" />
            </div>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <div class="lab-table-page">
      <div style="display: inline-flex">
        <el-pagination
            :disabled="requesting"
            :current-page="pageInfo.page"
            :page-sizes="[5, 10, 20, 50, 100]"
            :page-size="pageInfo.pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="pageInfo.total"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
        />
        <el-button-group style="padding: 2px 5px">
          <el-button icon="el-icon-refresh" title="刷新" :disabled="requesting" @click="loadSource([])" />
          <el-button icon="el-icon-setting" title="设置" :disabled="requesting" @click="settingVisible = true" />
        </el-button-group>
      </div>
    </div>
    <el-dialog title="表格列设置" :visible.sync="settingVisible" width="400px" append-to-body>
      <el-table :data="element.elements" height="400px">
        <el-table-column type="index" label="序号" width="50" align="center" />
        <el-table-column label="列名" align="center" prop="label"></el-table-column>
        <el-table-column label="展示范围" align="center" prop="lifeScope"></el-table-column>
        <el-table-column align="center" label="是否展示" prop="visible">
          <template slot-scope="scope">
            <el-checkbox v-model="scope.row[scope.column.property]" @change="(val) => {columnSetting(scope.row, val)}" :disabled="scope.row.lifeScope === 'form'">展示</el-checkbox>
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>

    <el-dialog :visible.sync="importVisible" width="450px" style="text-align: center">
      <el-upload
          :action="uploadUrl"
          :headers="headers"
          :on-success="uploadSuccess"
          :show-file-list="false"
          :before-upload="() => { importIng = true;return true}"
          drag
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能xlsx文件，且不超过2000行</div>
      </el-upload>
    </el-dialog>
  </div>
</template>

<script>
import LabBase from "../../mixins/LabBase";
import LabDrag from "../../mixins/LabDrag";
import LabRequest from "../../mixins/LabRequest";
import Util from "../../utils/Util";

export default {
  name: "LabTable",
  mixins: [LabBase,LabRequest,LabDrag],
  provide() {
    return {
      parentElement: this
    }
  },
  data() {
    return {
      // 过滤对象
      filterModel: {},
      // 过滤元素
      filterElements: {},
      // 设置窗口
      settingVisible: false,
      // excel导入
      importVisible: false,
      // 选择数据
      selectRows: [],
      // 当前选择项目主键值
      selectRowKeys: [],
      // 包含历史选择
      selectAllRowsKeys: [],
      // 展开行主键值
      expandRowKeys: [],
      // 导入状态
      importIng: false
    }
  },
  computed: {
    uploadUrl () {
      return this.$Util.mergeUrl(process.env.VUE_APP_BASE_API, '/model/importExcel/' + this.viewInfo.callModel + '?appId=' + this.appInfo.appId)
    },
    headers () {
      return { Authorization: 'Bearer ' + this.$AuthStorage.getAccessToken() }
    }
  },
  created() {
    this.$LabRender.autoFill(this.element, this)
    const { elements, selfType } = this.element
    elements.forEach(item => {
      this.$LabRender.autoFill(item, this)
      if (!Util.isEmpty(item.props.tableFilter)) {
        let filterRender = 'text'
        if (['number','rate','progress'].includes(item.render)) {
          filterRender = 'number'
        } else if (['date','daterange','datetime','datetimerange'].includes(item.render)) {
          filterRender = 'datetimerange'
        } else if (['select','radio','checkbox'].includes(item.render)) {
          filterRender = 'select'
        } else if (['switch'].includes(item.render)) {
          filterRender = 'switch'
        }
        const filterEl = this.$LabRender.create(filterRender,item.label,'table',item.mapper)
        Reflect.set(filterEl, 'selfType', 'edit')
        Reflect.set(filterEl.props, 'tableFilter', item.props.tableFilter)
        Reflect.set(filterEl.props, 'clearable', true)
        filterEl.events.push({
          trigger: 'change', eventScript: this.filterChange
        })
        if (!Util.isEmpty(item.requests)) {
          const source = item.requests.find(item => item.trigger === 'source')
          if (!Util.isEmpty(source)) {
            Reflect.set(filterEl, 'requests', [source])
          }
        }
        Reflect.set(this.filterElements, item.mapper, filterEl)
      }
    })
    if (Util.isEmpty(selfType)) {
      this.selfType = this.labDesign.switch ? 'edit' : 'view'
    }
    this.loadSource()
  },
  methods: {
    columnSetting(row) {
      const { label, mapper } = row
      this.$set(row, 'label', '设置中')
      setTimeout(() => {
        this.$set(row, 'label', label)
        const index = this.element.elements.findIndex(item => item.mapper === mapper)
        const changeItem = index > 0 ? this.element.elements[0] : this.element.elements[1]
        const changeLabel = changeItem.label
        this.$set(changeItem, 'label', '设置中')
        this.$set(changeItem, 'label', changeLabel)
      }, 50)
    },
    filterChange(){
      this.loadSource(this.addFilterByFilter)
    },
    addFilterByFilter(){
      const localFilters = []
      const keys = Object.keys(this.filterModel)
      keys.forEach(key => {
        const value = this.filterModel[key]
        if (!Util.isEmpty(value)) {
          const ele = this.filterElements[key]
          if (ele) {
            localFilters.push({ field: key, op: ele.props.tableFilter || 'like', value  })
          }
        }
      })
      return localFilters
    },
    handleSizeChange(val) {
      this.pageInfo.pageSize = val
      this.loadSource()
    },
    handleCurrentChange(val) {
      this.pageInfo.page = val
      this.loadSource()
    },
    loadSource(localFilters){
      this.dataSource.splice(0, this.dataSource.length)
      const { options } = this.element
      // 默认静态选项
      const list = Util.toArray(options)
      list.forEach(item => {
        this.dataSource.push(item)
      })
      const sourceRequest = this.findRequest('source')
      if (!sourceRequest || this.labDesign.switch) {
        if (this.dataSource.length === 0) {
          this.dataSource.push({})
        }
        return
      }
      const bodyArgs = this.getBody(sourceRequest,this.modelData)
      // 传入过滤
      if (!Util.isEmpty(localFilters)) {
        if (Util.isArray(localFilters)) {
          localFilters.forEach(item => this.addFilter(item))
        } else {
          this.addFilter(localFilters)
        }
      }
      // 表格头部过滤
      const filters = this.addFilterByFilter()
      if (!Util.isEmpty(filters)) {
        filters.forEach(item => this.addFilter(item))
      }
      this.selectRowKeys.splice(0, this.selectRowKeys.length)
      this.selectRows.splice(0, this.selectRows.length)
      this.dispatchRequest('source',this.modelData, bodyArgs)
          .then(res => {
            if (!Util.isEmpty(res)) {
              const totalProp = sourceRequest.totalProp || 'total'
              const dataProp = sourceRequest.dataProp || 'records'
              this.pageInfo.total = this.$Util.callPropValue(res, totalProp)
              this.dataSource = this.$Util.callPropValue(res, dataProp)
            } else {
              console.info('节点数据源请求:', this.element, res)
            }
            this.sourceFilters.splice(0, this.sourceFilters.length)
            setTimeout(() => {
              this.requesting = false
            }, 100)
          })
    },
    selectAll(selection) {
      this.selectRows = this.$Util.copy(selection)
      this.selectEvent()
    },
    select(selection, row) {
      this.selectRows = this.$Util.copy(selection)
      this.selectEvent()
    },
    selectEvent(){
      this.selectRowKeys.splice(0, this.selectRowKeys.length)
      const rowKey = this.element.props.rowKey
      if (rowKey) {
        this.selectRows.forEach(item => {
          this.selectRowKeys.push(item[rowKey])
        })
      }
      const args = { selectRows: this.selectRows, selectAllRows: this.selectAllRows, selectRowKeys: this.selectRowKeys }
      console.info('选中事件', args)
      this.dispatchEvent('select', args)
    },
    changeSelectAll(row, select) {
      const rowKey = this.element.props.rowKey
      if (!this.$Util.isEmpty(row) && !this.$Util.isEmpty(rowKey)) {
        const val = row[rowKey]
        if (this.$Util.isEmpty(val)) {
          return
        }
        let index = this.selectAllRows.findIndex(item => item[rowKey] === val)
        if (select) {
          index = index === -1 ? this.selectAllRows.length : index
          this.selectAllRows.splice(index, 0, row)
        } else if (index > -1) {
          this.selectAllRows.splice(index, 1)
        }
      }
    },
    rowClick(row, column) {
      if (!column || !column.property){
        return
      }
      const args = { selectRows: this.selectRows, selectRowKeys: this.selectRowKeys, row }
      console.info('点击事件', args)
      this.dispatchEvent('rowClick', args)
    },
    getDatas(select) {
      if (this.selectRows.length > 0) {
        return this.selectRows
      }
      return select ? [] : this.dataSource
    },
    addData(data) {
      if (!this.$Util.isObj(data)) {
        return;
      }
      const rowKey = this.element.props.rowKey
      data._key = this.$Util.uuid(6)
      const rowVal = data[rowKey]
      if (!this.$Util.isEmpty(rowVal)) {
        const index = this.dataSource.findIndex(item => item[rowKey] === rowVal)
        if (index < 0) {
          this.dataSource.splice(0, 0, data)
        } else {
          this.dataSource.splice(index, 1, data)
        }
      } else {
        this.dataSource.splice(0, 0, data)
      }
    },
    saveData(data, refreshProcess) {
      return new Promise(resolve => {
        if (data.length > 0) {
          this.saveByModel(data, refreshProcess)
              .then(res => {
                this.$resultMsg(this, res)
                if (res.code === 200) {
                  this.loadSource()
                }
                resolve(res)
              })
        } else {
          this.$resultMsg(this, {msg: '没有可保存的数据'})
          resolve({code: 200})
        }
      })
    },
    removeData(data, refreshProcess){
      return new Promise(resolve => {
        const list = this.$Util.isObj(data) ? [data] : data
        if (list.length < 1) {
          this.$resultMsg(this, {msg: '没有可删除的数据'})
          resolve({code: 200})
        }
        const removeDatas = []
        const rowKey = this.element.props.rowKey
        list.forEach(item => {
          const rowVal = item[rowKey]
          if (!this.$Util.isEmpty(rowVal)) {
            removeDatas.push(item)
          } else {
            const index = this.dataSource.findIndex(e => e._key === item._key)
            if (index >= 0) {
              this.dataSource.splice(index, 1)
            }
          }
        })
        if (removeDatas.length > 0) {
          this.removeByModel(removeDatas, refreshProcess)
              .then(res => {
                this.$resultMsg(this, res)
                if (res.code === 200) {
                  this.loadSource()
                }
                resolve(res)
              })
        } else {
          resolve({code: 200})
        }
      })
    },
    importExcel() {
      this.importVisible = true
    },
    exportExcel() {
      const { callModel } = this.viewInfo
      if (this.$Util.isEmpty(callModel)) {
        this.$resultMsg(this, { msg: '未获取到业务模型'})
        return
      }
      const query = this.$Util.base64Encode(JSON.stringify(this.pageInfo))
      const url = this.$Util.mergeUrl(process.env.VUE_APP_BASE_API, '/model/exportExcel/' + callModel)
      window.open(url + '?query=' + query + '&appId=' + this.appInfo.appId + '&access_token=' + this.$AuthStorage.getAccessToken())
    },
    uploadSuccess (response) {
      this.$resultMsg(this, response)
      if (response.code === 200) {
        this.loadSource()
        this.importVisible = false
      }
      this.importIng = false
    }
  }
}
</script>

<style lang="scss">
  .lab-table-page {
    display: flex;
    justify-content: flex-end;
    flex-flow: row nowrap;
  }
</style>
